package com.lsh.service.Impl;

import com.lsh.model.Label;
import com.lsh.repository.LabelRepository;
import com.lsh.service.LabelService;
import com.lsh.util.IdWorker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List;

/**
 * @author ：LiuShihao
 * @date ：Created in 2020/10/28 9:02 下午
 * @desc ：
 */
@Service
public class LabelServiceImpl implements LabelService {
    @Autowired
    LabelRepository repository;

    @Autowired
    IdWorker idWorker;

    @Override
    public List<Label> findAll() {
        return repository.findAll();
    }

    @Override
    public Label findById(String labelId) {
        return repository.findById(labelId).get();
    }

    @Override
    public void add(Label label) {
        // 使用雪花算法获得id
        label.setId(idWorker.nextId()+"");
        // 添加用save
        repository.save(label);

    }

    @Override
    public void update(Label label) {
        // 更新用save
        repository.save(label);
    }

    @Override
    public void deleteById(String labelId) {
        repository.deleteById(labelId);
    }

    @Override
    public List<Label> findSearch(Label label) {
        /**
         * 使用jpa的 findAll(Specification s)
         * 该参数是个接口 : 这里使用的是匿名内部类方式,没有再单独创建其子类
         */
        return repository.findAll(new Specification<Label>() {
            /**
             * @param root  根对象 : 要把条件封装进哪个对象  目的是将条件封装对象
             * @param criteriaQuery 封装查询的关键字:group by,order by等,其实无用!
             * @param criteriaBuilder 封装条件对象的   目的是封装条件对象
             * @return  如果直接返回null,表示不需要任何条件
             */
            @Nullable
            @Override
            public Predicate toPredicate(Root<Label> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                /**
                 * like()  模糊查询
                 * equal() 直接查询
                 * ------------------------
                 * root.get("labelname").as(String.class)
                 * 从封装的条件对象中获得要查询的字段,该字段是String类型
                 * 参数2 : 具体查询的条件
                 * 即整体的结果就相当于是
                 *  where labelname like "%张三%"
                 *  ------------------------
                 * 如果还有需要查询的条件就再来一个criteriaBuilder.like(...);
                 * 但是该criteriaBuilder.like()返回值是Predicate对象,正是toPredicate的返回值
                 * 如果多个criteriaBuilderlike()就会返回多个Predicate对象,那该如何返回?
                 * -------------------------
                 * criteriaBuilder提供了and(Predicate... p)方法,该方法返回值是Predicate对象
                 * and()方法的参数是Predicate类型的数组,即有多少查询条件就可以使用criteriaBuilder得当多少
                 * Predicate对象,然后放入Predicate类型的数组,再放入and()返回.
                 * 但是不确定有多少查询条件啊?即不确定该Predicate类型的数组的长度啊?
                 * -------------------------
                 * 使用集合存储.集合存储所有criteriaBuilder得当的Predicate对象,然后获得集合长度,利用该长度
                 * 创建数组,然后将该集合中的值传入数组,然后将数组放入and(),最终返回
                 * -------------------------
                 * and() 就好比 where name like "%张三%" and age = 1
                 */
                List<Predicate> list = new ArrayList<>();
                if(label.getLabelname() != null && !"".equals(label.getLabelname())) {
                    Predicate predicate = criteriaBuilder.like(root.get("labelname").as(String.class), "%" + label.getLabelname() + "%");
                    list.add(predicate);
                }
                if(label.getLabelname() != null && !"".equals(label.getLabelname())) {
                    Predicate predicate = criteriaBuilder.like(root.get("labelname").as(String.class), "%" + label.getLabelname() + "%");
                    list.add(predicate);
                }
                if(label.getState() != null && "".equals(label.getState())) {
                    // state = "1"
                    Predicate predicate = criteriaBuilder.equal(root.get("state").as(String.class), label.getState());
                    list.add(predicate);
                }
                Predicate[] predicates = list.toArray(new Predicate[list.size()]);
                // where like labelname "%张三%" and state = "1"
                return criteriaBuilder.and(predicates);
            }
        });

    }

    @Override
    public Page findSearchPage(Label label, int page, int size) {
        // Pageable是接口,PageRequest是其子类
        // jpa的第一页要设置为 0
        Pageable pageable = PageRequest.of(page-1,size);
        return repository.findAll(new Specification<Label>() {
            @Override
            public Predicate toPredicate(Root<Label> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> list = new ArrayList<>();
                if(label.getLabelname() != null && !"".equals(label.getLabelname())) {
                    Predicate predicate = criteriaBuilder.like(root.get("labelname").as(String.class), "%" + label.getLabelname() + "%");
                    list.add(predicate);
                    return predicate;
                }
                if(label.getState() != null && !"".equals(label.getState())) {
                    // state = "1"
                    Predicate predicate = criteriaBuilder.equal(root.get("state").as(String.class), label.getState());
                    list.add(predicate);
                }
                Predicate[] predicates = list.toArray(new Predicate[list.size()]);
                // where like labelname "%张三%" and state = "1"
                return criteriaBuilder.and(predicates);
            }
        },pageable);

    }
}
